package com.whosly.strategy.container;

import java.util.*;

import com.whosly.strategy.extractor.StrategyContainerExtractor;
import com.whosly.strategy.util.LoggerUtil;
import org.slf4j.Logger;

import com.google.common.base.Preconditions;
import com.whosly.strategy.IStrategy;
import com.whosly.strategy.extractor.GenericExtractor;
import com.whosly.strategy.spring.ManageSpringBeans;
import org.springframework.context.annotation.DependsOn;

/**
 * @param <C>
 *            条件类型
 * @param <S>
 *            策略类型
 *
 * @author 袁洋 2014年7月16日
 */
public abstract class StrategyContainerImpl<C, S extends IStrategy<C>> implements IStrategyContainer<C, S> {
	/**
	 * 根据策略类型及条件获取策略
	 *
	 * @param <D>
	 *            策略枚举类型
	 * @param <T>
	 *            策略接口
	 *
	 * @param strategyClass
	 *            策略类型
	 * @param condition
	 *            条件
	 * @return 该策略类型下满足指定条件的策略
	 */
	public static <D, T extends IStrategy<D>> T getStrategy(final Class<T> strategyClass, final D condition) {
		if(ManageSpringBeans.getContext() == null){
			return null;
		}

		final Collection<T> strategys = ManageSpringBeans.getBeans(strategyClass).values();
		for (final T t : strategys) {
			if (t.getCondition() == condition) {
				return t;
			}
		}
		return null;
	}

	/** Logger available to subclasses. */
	protected final Logger logger = LoggerUtil.get(getClass());

	private final Map<C, S> strategyMap = new HashMap<C, S>();

	// 被匿名内部类实现的 IStrategyContainer interface， 代理模式下使用
	private Class<IStrategyContainer<C, S>> strategyContainerTarget = null;

	@Deprecated
	public StrategyContainerImpl(){
	}

	public StrategyContainerImpl(Class<IStrategyContainer<C, S>> strategyContainerTarget){
		this.strategyContainerTarget = strategyContainerTarget;
	}

	@Override
	public S getStrategy(final C condition) {
		if (!strategyMap.containsKey(condition)) {
			initStrategyBean();
		}
		return strategyMap.get(condition);
	}

	/**
	 * @return the strategyMap
	 */
	protected Map<C, S> getStrategyMap() {
		return strategyMap;
	}

	/**
	 * 从spring context中直接提取对应的策略处理器，用以取代手工的registStrategy
	 *
	 * 只能应用于从StrategyContainerImpl继承的容器类，无法直接应用于StrategyContainerImpl对象
	 */
	protected synchronized void initStrategyBean() {
		Class<?> clazz = this.getClass();

		if (strategyMap.size() > 0) {
			logger.trace("{} has already been initialed", clazz.getName());
			return;
		}
		Preconditions.checkArgument(clazz != StrategyContainerImpl.class,
				"该方法无法直接应用于StrategyContainerImpl对象");

		Class<S> strategyClass;
		if(strategyContainerTarget != null){
			// 内明内部类处理，获取接口
			strategyClass = (Class<S>) GenericExtractor.getClass(StrategyContainerExtractor.getInterfaceType(strategyContainerTarget), 1, IStrategy.class);
		}else{
			// 常规类处理
			strategyClass = (Class<S>) GenericExtractor.getClass(StrategyContainerExtractor.getInterfaceType(this.getClass()), 1, IStrategy.class);
		}
		Preconditions.checkArgument(IStrategy.class.isAssignableFrom(strategyClass), "不符合范式要求(IStrategy)/"+ "[" + strategyClass + "]");

		Class<C> conditionClass;
		if(strategyContainerTarget != null){
			conditionClass = (Class<C>) GenericExtractor.getClass(StrategyContainerExtractor.getInterfaceType(strategyContainerTarget), 0);
		}else{
			conditionClass = (Class<C>) GenericExtractor.getClass(StrategyContainerExtractor.getInterfaceType(this.getClass()), 0);
		}

		final Collection<S> strategys = ManageSpringBeans.getBeans(strategyClass).values();
		logger.info("{} / {}[C] has {}[S]", clazz.getName(), conditionClass.getName(), strategys.size() + " " + strategyClass.getName());

		for (final S s : strategys) {
			logger.debug("{} / [{}],[{}]", clazz.getName(), s.getCondition(), s);
			Preconditions.checkArgument(!strategyMap.containsKey(s.getCondition()),
					"该类型已被注册过[" + s.getCondition() + "][" + s + "]");

			strategyMap.put(s.getCondition(), s);
		}
	}


}
